home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #23 (Aug 87) / library manager source / Library Manager < prev    next >
Text File  |  1987-07-13  |  14KB  |  561 lines

  1. UNIT LibMgr;
  2.  
  3. INTERFACE
  4.     USES
  5.         Rom85, HFS;
  6.  
  7.     TYPE
  8.         StandardType = (StandardGet, StandardPut);
  9.         Outcome = (Success, Error, Cancellation);
  10.         str63 = STRING[63];
  11.         str31 = STRING[31];
  12.         str80 = STRING[80];
  13.  
  14.         LmirPtr = ^Lmir;
  15.         LmirHdl = ^LmirPtr;
  16.  
  17.         LMIR = RECORD              {Library Manager Information Record}
  18.                 rsrcID : integer;
  19.                 volname : str31;
  20.                 vRef : integer;
  21.                 hfsvolume : boolean;
  22.                 DirID : Longint;
  23.                 filename : str63;
  24.                 fRefNum : integer;
  25.                 next, prev : LmirHdl;
  26.                 FTyp : integer;
  27.                 RecsOnFile, CurRec : integer;
  28.                 changed : boolean;
  29.                 Status : (Open, Closed, NotFound);
  30.             END;
  31.  
  32.     PROCEDURE GetPathInfo (vRefNum : integer;
  33.                                     VAR rootVol : Str31;
  34.                                     VAR hfsFlag : boolean;
  35.                                     VAR WDirID : longint);
  36.  
  37.  
  38.     FUNCTION OpenWD (VAR vRefNum : integer;
  39.                                     DirID : longint) : OSErr;
  40.  
  41.     PROCEDURE OpenLib (VAR whichLib : LmirHdl;
  42.                                     itsName : str255);
  43.  
  44.     PROCEDURE OpenLinkedLib (LinkTo : LmirHdl;
  45.                                     ResName : str255);
  46.  
  47.     FUNCTION CreateLib (VAR newLib : LmirHdl) : boolean;
  48.  
  49.     FUNCTION FindLib (VAR theLib : LmirHdl) : boolean;
  50.  
  51.     PROCEDURE RemoveLib (VAR whichFile : LmirHdl);       {Close file and remove from list of open libraries}
  52.  
  53.     PROCEDURE CloseLibList (Top : LmirHdl);                 {Close all open libraries in a given list and empty list}
  54.  
  55.     FUNCTION StandardFile (opCode : StandardType;
  56.                                     oldName : Str255;
  57.                                     fType : OSType;
  58.                                     VAR vRef : integer) : str63;
  59.  
  60.     PROCEDURE GetLibraryResource (VAR theLibrary : LmirHdl;
  61.                                     ResourceName : str255);
  62.  
  63. IMPLEMENTATION
  64.  
  65.     FUNCTION HFSRunning : boolean;
  66.         CONST
  67.             FSFCBLen = $3F6;
  68.         VAR
  69.             HFS : ^INTEGER;
  70.     BEGIN
  71.         HFS := POINTER(FSFCBLen);
  72.         HFSRunning := (HFS^ > 0);
  73.     END;
  74.  
  75.     FUNCTION NewRoms : boolean;
  76.         CONST
  77.             NewRomsID = 117;
  78.         VAR
  79.             RomVersion, Machine : INTEGER;
  80.     BEGIN
  81.         Environs(RomVersion, Machine);
  82.         NewRoms := RomVersion >= NewRomsID;
  83.     END;
  84.  
  85.     FUNCTION GetErrorMsg (Result : OSErr) : str80;
  86.     BEGIN
  87.         Result := abs(Result);
  88.  
  89.         CASE Result OF
  90.             33 : 
  91.                 GetErrorMsg := 'the file directory is full.  ';
  92.             34 : 
  93.                 GetErrorMsg := 'all allocation blocks on the volume are full.  ';
  94.             35 : 
  95.                 GetErrorMsg := 'the specified volume is not mounted.  ';
  96.             36 : 
  97.                 GetErrorMsg := 'there was an unspecified I/O Error.  ';
  98.             37 : 
  99.                 GetErrorMsg := 'the file name or volume name is bad (perhaps zero-length).  ';
  100.             39 : 
  101.                 GetErrorMsg := 'logical end-of-file was reached unexpetedly during read operation.  ';
  102.             40 : 
  103.                 GetErrorMsg := 'an attempt was made to position before start of file.  ';
  104.             42 : 
  105.                 GetErrorMsg := 'too many are files open.  ';
  106.             43 : 
  107.                 GetErrorMsg := 'the file could not be found.  ';
  108.             44 : 
  109.                 GetErrorMsg := 'the volume is locked by a hardware setting.  ';
  110.             45 : 
  111.                 GetErrorMsg := 'the file is locked';
  112.             46 : 
  113.                 GetErrorMsg := 'the volume is locked by a software flag.  ';
  114.             47 : 
  115.                 GetErrorMsg := 'the file is already in use.  ';
  116.             48 : 
  117.                 GetErrorMsg := 'a file with the specified name exists and cannot be overwritten.  ';
  118.             49 : 
  119.                 GetErrorMsg := 'the file is already open for read/write.  It cannot be reopened.  ';
  120.             50 : 
  121.                 GetErrorMsg := 'no volume was specified and there is no default volume. ';
  122.             51 : 
  123.                 GetErrorMsg := 'a non-existent path was specified.  ';
  124.             52 : 
  125.                 GetErrorMsg := 'there was an error finding current position in file.  ';
  126.             53 : 
  127.                 GetErrorMsg := 'the specified volume is not on-line.  ';
  128.             54 : 
  129.                 GetErrorMsg := 'there was an attempt to open a locked file for writing.  ';
  130.             55 : 
  131.                 GetErrorMsg := 'there was an attempt to mount an already mounted volume.  ';
  132.             56 : 
  133.                 GetErrorMsg := 'the specified drive number is not mounted.  ';
  134.             57 : 
  135.                 GetErrorMsg := 'the volume lacks Macintosh-format directory.  ';
  136.             58 : 
  137.                 GetErrorMsg := 'there was an external file system error.  ';
  138.             59 : 
  139.                 GetErrorMsg := 'there was a problem during rename.  ';
  140.             60 : 
  141.                 GetErrorMsg := 'the master directory block is bad; this volume must be reinitialized.  ';
  142.             61 : 
  143.                 GetErrorMsg := 'the read/write permission of the file/folder does not allow writing . ';
  144.             108 : 
  145.                 GetErrorMsg := 'there is insufficient application memory.  ';
  146.             120 : 
  147.                 GetErrorMsg := 'the directory could not be found.  ';
  148.             121 : 
  149.                 GetErrorMsg := 'too many working directories are open.  ';
  150.             122 : 
  151.                 GetErrorMsg := 'a folder cannot be placed in its own subfolder.  ';
  152.             123 : 
  153.                 GetErrorMsg := 'an attempt was made to do hierarchical operations on a nonhierarchical volume.  ';
  154.             127 : 
  155.                 GetErrorMsg := 'there was an internal file system error.  ';
  156.         END;
  157.     END;
  158.  
  159.     PROCEDURE UpdateResource (vanilla : handle);
  160.  
  161.     BEGIN
  162.  
  163.         ChangedResource(vanilla);
  164.         WriteResource(vanilla);
  165.  
  166.     END;
  167.  
  168.     PROCEDURE IOCheck (resultCode : OSErr);
  169.  
  170.         VAR
  171.             ignore : INTEGER;
  172.             errorString : Str255;
  173.  
  174.     BEGIN
  175.  
  176.         IF resultCode <> NoErr THEN
  177.             BEGIN
  178.                 NumToString(resultCode, errorString);
  179.                 ParamText('Macintosh Error #', errorString, ':  ', GetErrorMsg(resultCode));
  180.                 InitCursor;
  181.                 ignore := StopAlert(305, NIL);
  182.             END
  183.  
  184.     END;
  185.  
  186.     FUNCTION StandardFile;
  187.                         {opCode : StandardType;  oldName : Str255; fType : OSType; }
  188.                         {var vRef : integer) :  str63 }
  189.         VAR
  190.             where : Point;
  191.             reply : SFReply;
  192.             textType : SFTypeList;
  193.  
  194.     BEGIN
  195.         where.h := 80;
  196.         where.v := 55;
  197.         textType[0] := fType;
  198.         reply.vRefNum := vRef;
  199.         IF opCode = StandardGet THEN
  200.             SFGetFile(where, 'Select Application to Launch', NIL, 1, textType, NIL, reply)
  201.         ELSE
  202.             SFPutFile(where, '', oldName, NIL, reply);
  203.         WITH reply DO
  204.             IF NOT good THEN
  205.                 StandardFile := ''
  206.             ELSE
  207.                 BEGIN
  208.                     StandardFile := fName;
  209.                     vRef := vRefNum
  210.                 END
  211.     END;
  212.  
  213.     PROCEDURE HandleChanges (changedFile : LmirHdl);
  214.     BEGIN
  215.  
  216. {A boolean field in the LMIR can be set if your change records in memory but you do not}
  217. {immediately write them out to the file...}
  218.  
  219. {Then put whatever routines you need to handle updates to records in memory here}
  220.  
  221.     END;
  222.  
  223.     PROCEDURE RemoveLib; {var whichFile : LmirHdl);  }
  224.         VAR
  225.             ReturnValidHdl : LmirHdl;
  226.     BEGIN
  227.  
  228.         IF whichFile^^.changed THEN
  229.             HandleChanges(whichFile);
  230.         IF whichFile^^.status = Open THEN
  231.             IOCheck(FSClose(whichFile^^.fRefNum));
  232.         ReturnValidHdl := whichFile^^.next;
  233.         whichFile^^.prev^^.next := whichFile^^.next;
  234.         whichFile^^.next^^.prev := whichFile^^.prev;
  235.         whichFile^^.status := Closed;
  236.         UpdateResource(handle(whichFile));
  237.         ReleaseResource(handle(whichFile));
  238.         whichFile := ReturnValidHdl;
  239.     END;
  240.  
  241.     PROCEDURE CloseLibList; {Top : LmirHdl; }
  242.         VAR
  243.             next : LmirHdl;
  244.     BEGIN
  245.         next := Top^^.next;
  246.         REPEAT
  247.             RemoveLib(next);
  248.         UNTIL next = Top;
  249.         RemoveLib(Top);
  250.     END;
  251.  
  252.     FUNCTION OpenWD; {var vREfNum : integer;    }
  253. {                        DirID : longint)            }
  254. {                         : OSErr;                    }
  255.  
  256.         VAR
  257.             blk : WDPBRec;
  258.             Result : OSErr;
  259.  
  260.     BEGIN
  261.  
  262.         blk.ioCompletion := NIL;
  263.         Result := PBGetVol(@blk, false); {this just sets ioWDProcID to whatever...}
  264.  
  265.         IF Result = NoErr THEN
  266.             BEGIN
  267.                 WITH blk DO
  268.                     BEGIN
  269.                         ioNamePtr := NIL;
  270.                         ioVREfNum := vRefNum;
  271.                         ioWDDirID := DirID;
  272.                     END;
  273.  
  274.                 Result := PBOPenWD(@blk, false);
  275.                 vRefNum := blk.ioVRefNum;
  276.             END;
  277.  
  278.         OpenWD := Result;
  279.  
  280.     END;
  281.  
  282.  
  283.  
  284.     PROCEDURE GetPathInfo;
  285. {                         vRefNum : integer;             }
  286. {                         var rootVol  : Str31;        }
  287. {                         var hfsFlag : boolean );        }
  288. {                           var WDirID : longint;        }
  289.         VAR
  290.             blk : CInfoPBRec;
  291.             volBlk : HParamBlockRec;
  292.             dirname : str255;
  293.  
  294.     BEGIN
  295.         rootVol := '';
  296.         WITH volBlk DO
  297.             BEGIN
  298.                 ioCompletion := NIL;
  299.                 ioNamePtr := @rootVol;
  300.                 ioVRefNum := vRefNum;
  301.                 ioVolindex := 0;
  302.                 ioVSigWord := 0;
  303.                 IOCheck(PBHGetVINfo(@volBlk, false));
  304.             END;
  305.  
  306.         rootVol := Concat(rootVol, ':');
  307.         hfsFlag := HFSRunning;
  308.  
  309.         IF hfsFlag THEN
  310.             WITH blk DO
  311.                 BEGIN
  312.                     ioCompletion := NIL;
  313.                     dirname := '';
  314.                     ioNamePtr := @dirname;
  315.                     ioVRefNum := vRefNum;
  316.                     ioFDirINdex := -1;
  317.                     ioDrDirID := 0;
  318.                     IOCheck(PBGetCatINfo(@blk, false));
  319.                     WDirId := ioDrDirID;
  320.                 END;
  321.  
  322.     END;
  323.  
  324.     FUNCTION CreateLib; {newLib : LmirHdl; prompt : boolean) : boolean}
  325.  
  326.         CONST
  327.             null = '';
  328.         VAR
  329.             Result : OSERR;
  330.  
  331.     BEGIN
  332.         CreateLib := False;
  333.         WITH newLib^^ DO
  334.             BEGIN
  335.                 Filename := StandardFile(StandardPut, 'Make My Day', 'LMIR', vref);
  336.                 IF Filename <> null THEN
  337.                     BEGIN
  338.                         Result := Create(FileName, vRef, 'DAVE', 'LMIR');
  339.                         IF Result = NoErr THEN
  340.                             BEGIN
  341.                                 GetPathInfo(vRef, volName, hfsvolume, DirID);
  342.                                 CreateLib := True;
  343.                             END
  344.                         ELSE
  345.                             IOCheck(Result);
  346.                     END
  347.             END
  348.     END;
  349.  
  350.     FUNCTION UserWantsToCreateLib : boolean;
  351.         CONST
  352.             yes = 1;
  353.         VAR
  354.             p1, p2, p3, p4 : str80;
  355.             Response : integer;
  356.  
  357.     BEGIN
  358.  
  359.         p1 := 'Create a new library? ';
  360.         p2 := '';
  361.         p3 := '';
  362.         p4 := '';
  363.         ParamText(p1, p2, p3, p4);
  364.         InitCursor;
  365.         Response := CautionAlert(301, NIL);
  366.  
  367.         IF (Response = Yes) THEN
  368.             UserWantsToCreateLib := true
  369.         ELSE
  370.             UserWantsToCreateLib := false;
  371.     END;
  372.  
  373.     FUNCTION FindLib; {var  : theLib : LmirHdl; prompt : boolean; result : OSErr) : boolean}
  374.  
  375.         CONST
  376.             null = '';
  377.         VAR
  378.             dummy : OSERR;
  379.             SaveRef : integer;
  380.     BEGIN
  381.         FindLib := False;
  382.         WITH theLib^^ DO
  383.             BEGIN
  384.                 Filename := StandardFile(StandardGet, '', 'LMIR', vref);
  385.                 IF FileName <> null THEN
  386.                     BEGIN
  387.                         GetPathInfo(vRef, volName, hfsvolume, DirID);
  388.                         FindLib := True;
  389.                     END;
  390.             END;
  391.     END;
  392.  
  393.     FUNCTION UserWantsToFindLib (whichLib : LmirHdl;
  394.                                     Reference : Str255;
  395.                                     errorCode : OSErr) : boolean;
  396.         CONST
  397.             yes = 1;
  398.         VAR
  399.             p1, p2, p3, p4 : str80;
  400.             Response : integer;
  401.             UseName : str63;
  402.     BEGIN
  403.  
  404.         IF whichLib^^.filename = '' THEN
  405.             UseName := Reference
  406.         ELSE
  407.             UseName := whichLib^^.filename;
  408.  
  409.         p1 := ConCat('The ', UseName, ' File was not opened because ');
  410.         p2 := GetErrorMsg(ErrorCode);
  411.         p3 := 'Look for a library to open?  ';
  412.         p4 := '';
  413.         ParamText(p1, p2, p3, p4);
  414.         InitCursor;
  415.         Response := CautionAlert(301, NIL);
  416.  
  417.         IF (Response = Yes) THEN
  418.             UserWantsToFindLib := true
  419.         ELSE
  420.             UserWantsToFindLib := false;
  421.     END;
  422.  
  423.     PROCEDURE GetUserHelp (whichLibrary : LmirHdl;
  424.                                     ReferredToAs : str255;
  425.                                     ErrMsg : OSErr);
  426.         VAR
  427.             Intent, Attainment, Cancelled : boolean;
  428.     BEGIN
  429.         whichLibrary^^.status := NotFound;             {Guilty until proven innocent}
  430.         HLock(Handle(whichLibrary));
  431.  
  432.         IF UserWantsToFindLib(whichLibrary, ReferredToAs, ErrMsg) THEN
  433.             IF FindLib(whichLibrary) THEN
  434.                 BEGIN
  435.                     UpdateResource(Handle(whichLibrary));
  436.                     whichLibrary^^.status := Closed;
  437.                 END;
  438.  
  439.         IF whichLibrary^^.status = NotFound THEN            {User chose not to Open Existing File}
  440.             REPEAT
  441.                 Intent := UserWantsToCreateLib;
  442.                 IF Intent THEN
  443.                     Attainment := CreateLib(whichLibrary);
  444.                 IF Intent AND Attainment THEN
  445.                     BEGIN
  446.                         UpdateResource(Handle(whichLibrary));
  447.                         whichLibrary^^.status := Closed;
  448.                     END;
  449.             UNTIL (NOT Intent) OR (Attainment);
  450.  
  451.         HUnLock(Handle(whichLibrary));
  452.  
  453.     END;
  454.  
  455.     FUNCTION LibOpenedSuccessfully (LibToOpen : LmirHdl;
  456.                                     VAR Result : OSErr) : boolean;
  457.         VAR
  458.             fRefNum : integer;
  459.             SaveCurrentvol : integer;
  460.             Success : boolean;
  461.             Ignore : OSErr;
  462.     BEGIN
  463.         Success := False;
  464.         Ignore := GetVol(NIL, SaveCurrentVol);            {Save the default volume }
  465.         MoveHHI(Handle(LibToOpen));
  466.         HLock(Handle(LibToOpen));
  467.         WITH LibToOpen^^ DO
  468.             BEGIN
  469.                 result := SetVol(@volname, 0);                  {Is the root volume mounted?}
  470.                 IF Result = NoErr THEN
  471.                     result := GetVol(NIL, vRef);                     {Then make it default }
  472.                 IF (Result = NoErr) AND hfsVolume THEN        {Open the Working Directory}
  473.                     Result := OpenWD(vRef, DirID);
  474.                 IF Result = NoErr THEN                        {Vref is now correct whether HFS or MFS}
  475.                     Result := FSOpen(fileName, vRef, fRefNum);
  476.                 IF Result = NoErr THEN
  477.                     BEGIN
  478.                         Success := True;
  479.                         status := open;
  480.                     END;
  481.             END;
  482.  
  483.         HUnLock(Handle(LibToOpen));
  484.         LibOpenedSuccessfully := Success;
  485.         Ignore := SetVol(NIL, SaveCurrentVol);            {Restore the original default volume}
  486.     END;
  487.  
  488.     PROCEDURE InitLibResource (VAR Lib : LmirHdl;
  489.                                     LibName : str255);
  490.  
  491.     BEGIN
  492.  
  493.         Lib := LmirHdl(newHandle(SizeOf(Lmir)));
  494.         Lib^^.RsrcId := uniqueID('LMIR');
  495.         WITH Lib^^ DO
  496.             BEGIN
  497.                 vRef := 0;
  498.                 RecsOnFile := 0;
  499.                 filename := '';
  500.                 volname := '';
  501.                 DirID := 0;
  502.                 FTyp := 0;
  503.                 RecsOnFile := 0;
  504.                 CurRec := 0;
  505.                 status := NotFound;
  506.                 changed := false;
  507.             END;
  508.  
  509.         AddResource(Handle(Lib), 'LMIR', Lib^^.RsrcID, LibName);
  510.  
  511.     END;
  512.  
  513.     PROCEDURE GetLibraryResource; {var theLibrary : LmirHdl;  ResourceName : str255}
  514.     BEGIN
  515.  
  516.         IF NewRoms THEN
  517.             theLibrary := LmirHdl(Get1NamedResource('LMIR', ResourceName))
  518.         ELSE
  519.             theLibrary := LmirHdl(GetNamedResource('LMIR', ResourceName));
  520.     END;
  521.  
  522.     PROCEDURE OpenLib; {var whichLib : LmirHdl; itsName : str255}
  523.         VAR
  524.             Result : OSErr;
  525.     BEGIN
  526.  
  527.         GetLibraryResource(whichLib, itsName);
  528.         IF whichLib = NIL THEN
  529.             InitLibResource(whichLib, itsName);        {No resource even exists... Create one}
  530.  
  531. {Potential Problem #1 - The resource was *just* created by GetLibrary}
  532.         IF whichLib^^.status = NotFound THEN     {A resource exists, but no file }
  533.             GetUserHelp(whichLib, itsName, 43);
  534.  
  535. {Potential Problem #2 - The resource is there but the file couldn't be opened}
  536.         WHILE (whichLib^^.status = Closed) AND (NOT LibOpenedSuccessfully(whichLib, result)) DO
  537.             GetUserHelp(whichLib, itsName, Result);
  538.  
  539. {Note: if the user refuses to either look for or create a file, then status will be set to NotFound}
  540. {and the loop ends.  Of course, the loop also ends if a file is opened successfully.  }
  541.         whichLib^^.next := whichLib;
  542.         whichLib^^.prev := whichLib;
  543.     END;
  544.  
  545.     PROCEDURE OpenLinkedLib; {LinkTo : LmirHdl;}
  546. {                                    ResName : str255);}
  547.         VAR
  548.             newLib : LmirHdl;
  549.     BEGIN
  550.  
  551.         OpenLib(newLib, ResName);
  552.         newLib^^.next := LinkTo^^.next;
  553.         LinkTo^^.next := newLib;
  554.  
  555.         newLib^^.prev := LinkTo;
  556.         newLib^^.next^^.prev := newLib;
  557.  
  558.  
  559.     END;
  560.  
  561. END.